home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 23
/
AACD 23.iso
/
AACD
/
Online
/
opennap
/
kick.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-06-08
|
6KB
|
239 lines
/* Copyright (C) 2000-1 drscholl@users.sourceforge.net
This is free software distributed under the terms of the
GNU Public License. See the file COPYING for details.
$Id: kick.c,v 1.27 2001/02/15 08:39:45 drscholl Exp $ */
#include "opennap.h"
#include "debug.h"
int
is_chanop (CHANNEL * chan, USER * user)
{
LIST *list;
CHANUSER *chanUser;
for (list = chan->users; list; list = list->next)
{
chanUser = list->data;
ASSERT (chanUser->magic == MAGIC_CHANUSER);
if (chanUser->user == user)
return (chanUser->flags & ON_CHANNEL_OPERATOR);
}
return 0;
}
void
sync_channel_user (CONNECTION * con, CHANNEL * chan, CHANUSER * chanUser)
{
ASSERT (chan->local == 0);
/* have to correct for desync */
send_cmd (con, MSG_CLIENT_JOIN, ":%s %s", chanUser->user->nick,
chan->name);
/* restore channel flags */
if (chanUser->flags & ON_CHANNEL_OPERATOR)
send_cmd (con, MSG_CLIENT_OP, ":%s %s %s :%u",
Server_Name, chan->name, chanUser->user->nick,
chan->timestamp);
if (chanUser->flags & ON_CHANNEL_VOICE)
send_cmd (con, MSG_CLIENT_CHANNEL_VOICE, ":%s %s %s :%u",
Server_Name, chan->name, chanUser->user->nick,
chan->timestamp);
if (chanUser->flags & ON_CHANNEL_MUZZLED)
send_cmd (con, MSG_CLIENT_CHANNEL_MUZZLE, ":%s %s %s \"\" %u",
Server_Name, chan->name, chanUser->user->nick,
chan->timestamp);
}
/* 10202 [ :<sender> ] <channel> <user> [ "<reason>" ] */
HANDLER (kick)
{
char *av[3];
char *senderName;
int ac = -1;
USER *user, *sender;
CHANNEL *chan;
CHANUSER *chanUser;
(void) len;
ASSERT (validate_connection (con));
if (pop_user_server (con, tag, &pkt, &senderName, &sender))
return;
if (pkt)
ac = split_line (av, FIELDS (av), pkt);
if (ac < 2)
{
unparsable (con);
return;
}
chan = hash_lookup (Channels, av[0]);
if (!chan)
{
nosuchchannel (con);
return;
}
if (chan->local && ISSERVER (con))
{
log ("kick: server %s accessed local channel %s", con->host,
chan->name);
return;
}
user = hash_lookup (Users, av[1]);
if (!user)
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH,
"channel kick failed: no such user");
return;
}
if (sender && sender->level < LEVEL_MODERATOR)
{
if (list_find (sender->channels, chan) == 0)
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH,
"channel kick failed: you are not on that channel");
return;
}
else if (!is_chanop (chan, sender))
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH,
"channel kick failed: you are not channel operator");
return;
}
}
/* check if the target user is on the given channel */
chanUser = find_chanuser (chan->users, user);
if (!chanUser)
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH,
"channel kick failed: user is not on that channel");
return;
}
if (ac > 2)
truncate_reason (av[2]);
if (!chan->local)
pass_message_args (con, tag, ":%s %s %s \"%s\"", senderName,
chan->name, user->nick, (ac > 2) ? av[2] : "");
if (ISUSER (user->con))
{
char *who;
if (sender && sender->cloaked && user->level < LEVEL_MODERATOR)
who = "Operator";
else
who = senderName;
send_cmd (user->con, MSG_CLIENT_PART, chan->name);
send_cmd (user->con, MSG_SERVER_NOSUCH,
"You were kicked from channel %s by%s %s: %s",
chan->name, !sender ? "server " : "",
who, ac > 2 ? av[2] : "");
}
user->channels = list_delete (user->channels, chan);
notify_ops (chan, "%s%s kicked %s out of channel %s: %s",
!sender ? "Server " : "",
senderName, user->nick, chan->name, ac > 2 ? av[2] : "");
/* has to come after the notify_ops() since it uses chan->name and
chan may disappear if there are no users left
Greg Prosser <greg@snickers.org> */
part_channel (chan, user);
}
/* 820 [ :<sender> ] <channel> ["reason"] */
HANDLER (clear_channel)
{
CHANNEL *chan;
CHANUSER *chanUser;
USER *sender;
LIST *list;
char *chanName, *senderName;
(void) len;
ASSERT (validate_connection (con));
if (pop_user_server (con, tag, &pkt, &senderName, &sender))
return;
chanName = next_arg (&pkt);
if (!chanName)
{
unparsable (con);
return;
}
chan = hash_lookup (Channels, chanName);
if (!chan)
{
nosuchchannel (con);
return;
}
if (!sender)
{
log ("clear_channel: error, server %s tried to clear channel %s",
con->host, chanName);
return;
}
if (chan->local && ISSERVER (con))
{
log ("clear_channel: server %s cleared local channel %s",
con->host, chan->name);
return;
}
if (sender->level < LEVEL_MODERATOR && !is_chanop (chan, sender))
{
if (ISUSER (con))
send_cmd (con, MSG_SERVER_NOSUCH,
"channel clear failed: not channel operator");
return;
}
if (pkt)
truncate_reason (pkt);
if (!chan->local)
pass_message_args (con, tag, ":%s %s %s", sender->nick, chan->name,
NONULL (pkt));
notify_ops (chan, "%s cleared channel %s: %s", sender->nick,
chan->name, NONULL (pkt));
list = chan->users;
while (list)
{
ASSERT (VALID_LEN (list, sizeof (LIST)));
chanUser = list->data;
ASSERT (chanUser->magic == MAGIC_CHANUSER);
/* part_channel() may free the current `list' pointer so we advance
it here prior to calling it */
list = list->next;
/* this used to avoid kicking users of a higher level, but that
* lead to many desyncs. just make it all all-or-nothing event.
* mods+ can always bypass any channel restrictions anyway
*/
if (chanUser->user != sender)
{
chanUser->user->channels =
list_delete (chanUser->user->channels, chan);
if (ISUSER (chanUser->user->con))
{
send_cmd (chanUser->user->con, MSG_CLIENT_PART, "%s",
chan->name);
send_cmd (chanUser->user->con, MSG_SERVER_NOSUCH,
"%s cleared channel %s: %s", sender->nick,
chan->name, NONULL (pkt));
}
part_channel (chan, chanUser->user);
}
}
}